package com.cortex.papaya.view;

import java.util.ArrayList;
import java.util.List;

import com.cortex.papayasearch.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;

public class PieHalfView extends View {


	// the default of this view is the right side

	private Paint paint;
	private float rotation=0;
	private int piePieces;
	private float sweepAnglePiece;
	private float centerY;
	private float centerX;
	private float radius;

	private int moveX;
	private int moveY;
	private int lastX;
	private int lastY;
	private int speed;

	private PositionEnum position;
	private List<String> items;
	private int textSize;
	private int centerPiece;
	private int heightPiece;
	private int widthPiece;
	private int maxCharactersInPiece;
	private int selectedItem=0;

	private SelectedPieceChangedListener selectedPieceChangedListener;

	public PieHalfView(Context context) {
		super(context);
	}
	public PieHalfView(Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.PieHalfView);

		final int N = a.getIndexCount();
		for (int i = 0; i < N; ++i)
		{
			int attr = a.getIndex(i);
			switch (attr)
			{
			case R.styleable.PieHalfView_pieces:
				piePieces = a.getInt(attr, 8);
				break;
			case R.styleable.PieHalfView_speed:
				speed = a.getInt(attr, 5);
				break;
			case R.styleable.PieHalfView_direction:
				position = PositionEnum.values()[a.getInt(attr, 3)];
				break;
			case R.styleable.PieHalfView_textSize:
				textSize = a.getInt(attr, 20);
				break;

			}


		}
		a.recycle();
		sweepAnglePiece = (360.0f / piePieces);

	}
	public PieHalfView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}
	private void initSize(){
		calculateCenterPiece();
		calculateHeightPiece();
		calculateMaxCharactersInPiece();
		switch(position){
		case BOTTOM:
			radius = getWidth()/2;
			centerX = radius;
			centerY = getHeight();
			break;
		case LEFT:
			radius = getHeight()/2;
			centerX = 0;
			centerY = radius;
			break;
		case RIGHT:
			radius = getHeight()/2;
			centerX = getWidth();
			centerY = radius;
			break;
		case TOP:
			radius = getWidth()/2;
			centerX = radius;
			centerY = 0;
			break;
		default:
			break;
		}
	}
	private void defaultInit(){
		position = PositionEnum.RIGHT;
		speed = 5;
		piePieces = 10;
		sweepAnglePiece = (360.0f / piePieces);
		textSize = 20;
	}
	public int getPiePieces() {
		return piePieces;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}
	public int getSpeed() {
		return speed;
	}
	public float getRadius() {
		return radius;
	}
	public void setPieDirection(PositionEnum pieDirection) {
		this.position = pieDirection;
		invalidate();
	}
	public PositionEnum getPieDirection() {
		return position;
	}
	public void setCenterX(float centerX) {
		this.centerX = centerX;
		invalidate();
	}
	public float getCenterX() {
		return centerX;
	}
	public void setCenterY(float centerY) {
		this.centerY = centerY;
		invalidate();
	}
	public float getCenterY() {
		return centerY;
	}
	public void setTextSize(int textSize){
		this.textSize = textSize;
		invalidate();
	}
	public int getTextSize() {
		return textSize;
	}
	public void setItems(List<String> items){
		this.items = items;
		piePieces = items.size();
		sweepAnglePiece = 360.0f/piePieces;
		invalidate();
	}
	public void setSelectedItem(int index){
		float amountRotation = Math.abs(selectedItem-index)*sweepAnglePiece;
		rotation +=amountRotation;
		selectedItem = index;
		invalidate();
		
	}
	public void setOnSelectedPieceChangedListener(SelectedPieceChangedListener selectedPieceChangedListener) {
		this.selectedPieceChangedListener = selectedPieceChangedListener;
	}
	private Paint getPaint(){
		if (paint == null) {
			paint = new Paint();
			paint.setColor(Color.RED);
			paint.setTextSize(textSize);
		}
		return paint;
	}
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawPie(canvas);
		sendMessageToListener();
	}
	private void drawPie(Canvas canvas) {
		canvas.save();
		// draw circle
		getPaint().setColor(Color.RED);
		canvas.rotate(rotation, centerX, centerY);
		canvas.drawCircle(centerX, centerY, radius, getPaint());

		// divide circle and set text on each piece of circle
		for (int i = 0; i < piePieces; i++) {
			getPaint().setColor(Color.BLUE);
			Path path = new Path();
			String s=items.get(i);
			if(s.length()>maxCharactersInPiece+3){
				s = s.substring(0, maxCharactersInPiece);
				s += "...";
			}
			if(selectedItem == i){
				getPaint().setColor(Color.GREEN);
			}
			switch(position){
			case BOTTOM:
				getPaint().getTextPath(s, 0, s.length(), centerX, centerY-heightPiece+getPaint().getTextSize(), path);
				// before drawing the path should be closed
				path.close(); // not required on 2.2/2.3 devices
				canvas.drawPath(path, getPaint());				
				canvas.drawLine(centerX, centerY, centerX, centerY-radius, getPaint());
				break;
			case LEFT:
				canvas.save();
				canvas.rotate(sweepAnglePiece,centerX+(heightPiece/2),centerY);
				getPaint().getTextPath(s, 0, s.length(), centerX+heightPiece-getTextSize()*s.length(), centerY-centerPiece, path);
				// before drawing the path should be closed
				path.close(); // not required on 2.2/2.3 devices
				canvas.drawPath(path, getPaint());
				canvas.restore();
				canvas.drawLine(centerX, centerY, centerX+heightPiece, centerY, getPaint());
				break;
			case TOP:
				getPaint().getTextPath(s, 0, s.length(), centerX, centerY+heightPiece-getPaint().getTextSize(), path);
				// before drawing the path should be closed
				path.close(); // not required on 2.2/2.3 devices
				canvas.drawPath(path, getPaint());
				canvas.drawLine(centerX, centerY, radius, centerY+radius, getPaint());

				break;
			case RIGHT:
			default:
				getPaint().getTextPath(s, 0, s.length(), centerX-radius,centerY, path);
				// before drawing the path should be closed
				path.close(); // not required on 2.2/2.3 devices
				canvas.drawPath(path, getPaint());
				//				canvas.restore();
				canvas.drawLine(centerX, centerY, centerX+radius, centerY, getPaint());
				break;

			}
			canvas.rotate(sweepAnglePiece, centerX, centerY);
		}
		canvas.restore();
	}
	private void calculateCenterPiece(){
		float sideTriangleA = radius;
		float angleBase = (180-sweepAnglePiece)/2;
		float angleVertex = sweepAnglePiece;
		float base;
		// by Law sinuses
		float sinAngleBase = (float) Math.sin(Math.toRadians(angleBase));
		float sinAngleVertex = (float) Math.sin(Math.toRadians(angleVertex));
		base = (sideTriangleA/sinAngleBase)*sinAngleVertex;
		centerPiece = (int) (base/2);
		widthPiece = (int) base;
	}
	private void calculateHeightPiece(){
		float longSide = radius;
		float angleBase = (180-sweepAnglePiece)/2;
		float x;
		// by Law sinuses
		float sinAngleBase = (float) Math.sin(Math.toRadians(angleBase));
		x = sinAngleBase*longSide;
		heightPiece = (int) x;
	}
	private void calculateMaxCharactersInPiece(){
		if(position == PositionEnum.LEFT || position == PositionEnum.RIGHT){
			maxCharactersInPiece = (heightPiece*3/4)/getTextSize();
		}
		else{
			maxCharactersInPiece = widthPiece/getTextSize();
		}
	}
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		if(position == null){
			defaultInit();
		}
		int desiredWidth;
		int desiredHeight;
		
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);

		
		switch(position){
		case TOP:
		case BOTTOM:
			// set default width and height when the view top or bottom screen
			desiredWidth = (int) widthSize;
			desiredHeight = (int) widthSize/2;
			break;
		case RIGHT:
		case LEFT:
		default:
			// set default width and height when the view left or right screen
			desiredWidth = (int) heightSize/2;
			desiredHeight = (int) heightSize;
			break;

		}
		
		int width;
		int height;

		//Measure Width
		if (widthMode == MeasureSpec.EXACTLY) {
			//set specific size 400dp or something like this 
			width = widthSize;
		} else if (widthMode == MeasureSpec.AT_MOST) {
			// set size like parent
			//Can't be bigger than...
			width = Math.min(desiredWidth, widthSize);
		} else {
			//Be whatever you want
			width = desiredWidth;
		}

		//Measure Height
		if (heightMode == MeasureSpec.EXACTLY) {
			//set specific size 400dp or something like this 
			height = heightSize;
		} else if (heightMode == MeasureSpec.AT_MOST) {
			// set size like parent
			//Can't be bigger than...
			height = Math.min(desiredHeight, heightSize);
		} else {
			//Be whatever you want
			height = desiredHeight;
		}

		//MUST CALL THIS
		setMeasuredDimension(width, height);
		initSize();
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			lastX = (int)event.getX();
			lastY = (int)event.getY();
			return true;
		case MotionEvent.ACTION_MOVE:
			moveX = (int)event.getX();
			moveY = (int)event.getY();
			switch(position){
			case BOTTOM:
				if(lastX>moveX){
					rotation -= speed;
				}
				else if(lastX<moveX){
					rotation += speed;
				}
				break;
			case LEFT:
				if(lastY>moveY){
					rotation += speed;
				}
				else if(lastY<moveY){
					rotation -= speed;
				}
				break;
			case RIGHT:
				if(lastY<moveY){
					rotation -= speed;
				}
				else if(lastY>moveY){
					rotation += speed;
				}
				break;
			case TOP:
				if(lastX>moveX){
					rotation += speed;
				}
				else if(lastX<moveX){
					rotation -= speed;
				}
				break;
			default:
				return false;
			}
			// reset rotation
			if(Math.abs(rotation) >= 360){
				rotation = Math.abs(rotation)-360;
			}
			for (int i = 0; i <= items.size()-1; i++) {
				if(rotation>sweepAnglePiece*i && rotation<sweepAnglePiece*(i+1) ||
						360+rotation>sweepAnglePiece*i && 360+rotation<sweepAnglePiece*(i+1)){
					selectedItem = items.size()-i;
					if(i==0){
						selectedItem = i;
					}
					break;
				}
			}
			invalidate();
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			break;
		}
		lastX = moveX;
		lastY = moveY;
		return super.onTouchEvent(event);
	}
	private void sendMessageToListener(){
		if(selectedPieceChangedListener != null){
			selectedPieceChangedListener.selectedPieceChanged(items.get(selectedItem),selectedItem);
		}
	}
	public interface SelectedPieceChangedListener{
		void selectedPieceChanged(String item,int index);
	}
	private enum PositionEnum{
		TOP,
		BOTTOM,
		LEFT,
		RIGHT
	}
}